#include "crossbit/RBThread.h"
#include <iostream>

using namespace crossbit;

RBFuncIndx RBFuncTable[RBFUNCNUM] = {
	{4,"pthread_create",(XTMemAddr)(RBThreadManager::RBThreadCreate)},
	{2,"pthread_join",(XTMemAddr)(RBThreadManager::RBThreadJoin)},
	{2,"pthread_cleanup_push",(XTMemAddr)(RBThreadManager::RBThreadCleanupPush)},
	{1,"pthread_exit",(XTMemAddr)(RBThreadManager::RBThreadExit)}
};

void RBThreadManager::RBThreadCreate(RBThreadManager *_this, XTInt32 *thread_id, void *attr, void * (start_routine)(void*), void *arg)
{
	std::cout<<"RBThreadCreate is invoked!!"<<std::endl;
	XTInt32 stk_size = sizeof(XTInt32) * 4096;
	XTUint32* stk_limit = (XTUint32*) malloc(stk_size);	
	memset((char*) stk_limit, 0, stk_size);
	XTUint32 *stk_top = stk_limit + stk_size - sizeof(XTUint32);
	stk_top = (XTUint32*) ((XTMemAddr) stk_top & 0xfffffff4);
	//*(stk_top--) = (XTMemAddr) arg;
	//*(stk_top--) = (XTMemAddr) start_routine;
	//*(stk_top--) = (XTMemAddr) attr;
	//*stk_top= (XTMemAddr) thread_id;

	*(stk_top - 2) = (XTMemAddr) _this->rb_processor_state->reg(1); //????set $at
	*(stk_top - 26) = (XTMemAddr) start_routine; //set $t9
	*(stk_top - 29) = (XTMemAddr) _this->rb_processor_state->reg(28); //set $gp
	*(stk_top - 30) = (XTMemAddr) stk_top;  //set original $sp;
	*(stk_top - 31) = (XTMemAddr) stk_top;  //set original $s8/fp;
	*(stk_top - 32) = 0x4004c8;  //set ra;
	stk_top -= 68;

	//printf("sp of newthread is 0x%x\n", (XTInt32) *(stk_top+38));
	Thread newthread; 
	newthread.thread_id = (ThreadId) thread_id;
	newthread.stack_pointer = (XTMemAddr) stk_top;
	newthread.stack_limit = (XTMemAddr) stk_limit;
	newthread.next_PC = (XTMemAddr) start_routine;
	_this->thread_tbl.insert(std::pair<ThreadId, Thread>((ThreadId) thread_id, newthread));

	// set return value
	_this->rb_processor_state->put(2, 0x0);

	//_this->rb_processor_state->put(29, (XTInt32) stk_base);
	//_this->rb_memory_image->setupStack((XTMemAddr)stk_base);	

	_this->RBSchedule();
}


void RBThreadManager::RBThreadCleanupPush(RBThreadManager *_this, void * (routine)(void*), void *arg)
{
	std::cout<<"RBThreadCleanupPush is invoked!!"<<std::endl;
}

void RBThreadManager::RBThreadJoin(RBThreadManager *_this, XTInt32 thread_id, void **status)
{
	std::cout<<"RBThreadJoin is invoked!!"<<std::endl;
}

void RBThreadManager::RBThreadExit(RBThreadManager *_this, void *status)
{
	std::cout<<"RBThreadExit is invoked!!"<<std::endl;
}

void RBThreadManager::RBSchedule()
{
	//decide which thread to run


	
	//schedule the thread
	//save thread info of the current thread

	
	//load thread info of the go-to thread
	std::map<ThreadId, Thread>::iterator tt_iter = thread_tbl.begin();
	Thread thread_to = tt_iter->second;
	for(XTInt32 i = 33; i >= 0; i--)
	{
		rb_processor_state->fpPut(i, *((XTInt32*)thread_to.stack_pointer));	
		thread_to.stack_pointer += 4;
	}
	for(XTInt32 k = 33; k >= 0; k--)
	{
		rb_processor_state->put(k, *((XTInt32*)thread_to.stack_pointer));	
		thread_to.stack_pointer += 4;
	}

	//rb_processor_state->dump();

	GLOBAL::INTERCHANGE = 1;
	GLOBAL::NEXT_PC = thread_to.next_PC;
}
